// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包sql提供了一个围绕sql（或类似sql的）
// 数据库的通用接口。
// 
// sql包必须与数据库驱动程序结合使用。
// 参见https:
// 
// 查询完成后，不支持上下文取消的驱动程序在
// 之前不会返回。
// 
// 有关用法示例，请参阅位于
// golang.org/s/sqlwiki.
package sql

import (
	"context"
	"database/sql/driver"
	"errors"
	"fmt"
	"io"
	"reflect"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

var (
	driversMu sync.RWMutex
	drivers   = make(map[string]driver.Driver)
)

// nowFunc返回当前时间；它在测试中被覆盖。
var nowFunc = time.Now

// Register通过提供的名称使数据库驱动程序可用。
// 如果使用相同的名称调用寄存器两次，或者如果驱动程序为零，则
// 它会崩溃。
func Register(name string, driver driver.Driver) {
	driversMu.Lock()
	defer driversMu.Unlock()
	if driver == nil {
		panic("sql: Register driver is nil")
	}
	if _, dup := drivers[name]; dup {
		panic("sql: Register called twice for driver " + name)
	}
	drivers[name] = driver
}

func unregisterAllDrivers() {
	driversMu.Lock()
	defer driversMu.Unlock()
	// 用于测试。
	drivers = make(map[string]driver.Driver)
}

// Drivers返回已注册驱动程序名称的排序列表。
func Drivers() []string {
	driversMu.RLock()
	defer driversMu.RUnlock()
	list := make([]string, 0, len(drivers))
	for name := range drivers {
		list = append(list, name)
	}
	sort.Strings(list)
	return list
}

// NamedArg是一个命名参数。NamedArg值可以用作查询或Exec的
// 参数，并绑定到SQL语句中相应的命名
// 参数。
// 
// 有关创建NamedArg值的更简洁方法，请参阅
// 命名函数。
type NamedArg struct {
	_Named_Fields_Required struct{}

	// Name是参数占位符的名称。
	// 
	// 如果为空，参数列表中的序号位置将被
	// 使用。
	// 
	// 名称必须省略任何符号前缀。wen jian defg
	Name string

	// 它可能被分配与查询
	// 参数相同的值类型。
	Value any
}

// Named提供了一种更简洁的方法来创建NamedArg值。
// 
// 示例用法：
// 
// db。ExecContext（ctx，`
// 从发票中删除
// 其中
// 创建时间<@end 
// 和创建时间>=@start；`，
// sql.Named（“start”，startTime），
// sql。命名为（“end”，endTime），
// ）
func Named(name string, value any) NamedArg {
	// 这个方法之所以存在，是因为go1compat承诺
	// 不能保证结构不会增加更多的字段，
	// 所以未定义的结构文本是一个vet错误。因此，我们不想允许sql。NamedArg{name，value}。
	return NamedArg{Name: name, Value: value}
}

// IsolationLevel是TxOptions中使用的事务隔离级别。
type IsolationLevel int

// 驱动程序在BeginTx中可能支持的各种隔离级别。
// 如果驱动程序不支持给定的隔离级别，则可能会返回错误。
// 参见https:
const (
	LevelDefault IsolationLevel = iota
	LevelReadUncommitted
	LevelReadCommitted
	LevelWriteCommitted
	LevelRepeatableRead
	LevelSnapshot
	LevelSerializable
	LevelLinearizable
)

// String返回事务隔离级别的名称。
func (i IsolationLevel) String() string {
	switch i {
	case LevelDefault:
		return "Default"
	case LevelReadUncommitted:
		return "Read Uncommitted"
	case LevelReadCommitted:
		return "Read Committed"
	case LevelWriteCommitted:
		return "Write Committed"
	case LevelRepeatableRead:
		return "Repeatable Read"
	case LevelSnapshot:
		return "Snapshot"
	case LevelSerializable:
		return "Serializable"
	case LevelLinearizable:
		return "Linearizable"
	default:
		return "IsolationLevel(" + strconv.Itoa(int(i)) + ")"
	}
}

var _ fmt.Stringer = LevelDefault

// TxOptions保存要在DB中使用的事务选项。贝金特斯。
type TxOptions struct {
	// 隔离是事务隔离级别。
	// 如果为零，则使用驱动程序或数据库的默认级别。
	Isolation IsolationLevel
	ReadOnly  bool
}

// RawBytes是一个字节片，它包含对数据库本身拥有的内存的引用。扫描到RawBytes后，该片仅
// 有效，直到下一次调用next、Scan或Close。
type RawBytes []byte

// NullString表示可能为null的字符串。
// NullString实现了Scanner接口，因此
// 它可以用作扫描目标：
// 
// var s NullString 
// err:=db。QueryRow（“从foo中选择名称，其中id=？”，id）。扫描（&s）
// /。。。
// 如果s.Valid{
// 
// }否则{
// 
// }
// 
type NullString struct {
	String string
	Valid  bool // 如果字符串不为空，则有效
}

// 扫描实现扫描仪接口。
func (ns *NullString) Scan(value any) error {
	if value == nil {
		ns.String, ns.Valid = "", false
		return nil
	}
	ns.Valid = true
	return convertAssign(&ns.String, value)
}

// Value实现驱动程序估值器接口。
func (ns NullString) Value() (driver.Value, error) {
	if !ns.Valid {
		return nil, nil
	}
	return ns.String, nil
}

// NullInt64表示可能为null的int64。
// NullInt64实现了Scanner接口，因此
// 它可以用作扫描目标，类似于NullString。
type NullInt64 struct {
	Int64 int64
	Valid bool // 如果Int64不为空，则有效
}

// 扫描实现扫描仪接口。
func (n *NullInt64) Scan(value any) error {
	if value == nil {
		n.Int64, n.Valid = 0, false
		return nil
	}
	n.Valid = true
	return convertAssign(&n.Int64, value)
}

// Value实现驱动程序估值器接口。
func (n NullInt64) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return n.Int64, nil
}

// NullInt32表示可能为null的int32。
// NullInt32实现扫描仪接口，因此
// 它可以用作扫描目标，类似于NullString。
type NullInt32 struct {
	Int32 int32
	Valid bool // 如果Int32不为空，则有效
}

// 扫描实现扫描仪接口。
func (n *NullInt32) Scan(value any) error {
	if value == nil {
		n.Int32, n.Valid = 0, false
		return nil
	}
	n.Valid = true
	return convertAssign(&n.Int32, value)
}

// Value实现驱动程序估值器接口。
func (n NullInt32) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return int64(n.Int32), nil
}

// NullInt16表示可能为null的int16。
// NullInt16实现了Scanner接口，因此
// 它可以用作扫描目标，类似于NullString。
type NullInt16 struct {
	Int16 int16
	Valid bool // 如果Int16不为空，则有效
}

// 扫描实现扫描仪接口。
func (n *NullInt16) Scan(value any) error {
	if value == nil {
		n.Int16, n.Valid = 0, false
		return nil
	}
	err := convertAssign(&n.Int16, value)
	n.Valid = err == nil
	return err
}

// Value实现驱动程序估值器接口。
func (n NullInt16) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return int64(n.Int16), nil
}

// NullByte表示可能为null的字节。
// NullByte实现了Scanner接口，因此可以将其用作扫描目标，类似于NullString。
type NullByte struct {
	Byte  byte
	Valid bool // 如果字节不为空，则有效
}

// 扫描实现扫描仪接口。
func (n *NullByte) Scan(value any) error {
	if value == nil {
		n.Byte, n.Valid = 0, false
		return nil
	}
	err := convertAssign(&n.Byte, value)
	n.Valid = err == nil
	return err
}

// Value实现驱动程序估值器接口。
func (n NullByte) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return int64(n.Byte), nil
}

// NullFloat64表示可能为空的float64。
// NullFloat64实现了Scanner接口，因此可以将其用作扫描目标，类似于NullString。
type NullFloat64 struct {
	Float64 float64
	Valid   bool // 如果Float64不为空，则有效
}

// 扫描实现扫描仪接口。
func (n *NullFloat64) Scan(value any) error {
	if value == nil {
		n.Float64, n.Valid = 0, false
		return nil
	}
	n.Valid = true
	return convertAssign(&n.Float64, value)
}

// Value实现驱动程序估价师接口。
func (n NullFloat64) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return n.Float64, nil
}

// NullBool表示可能为null的bool。
// NullBool实现了Scanner接口，因此可以将其用作扫描目标，类似于NullString。
type NullBool struct {
	Bool  bool
	Valid bool // 如果Bool不为空，则为true有效
}

// 扫描实现扫描仪接口。
func (n *NullBool) Scan(value any) error {
	if value == nil {
		n.Bool, n.Valid = false, false
		return nil
	}
	n.Valid = true
	return convertAssign(&n.Bool, value)
}

// Value实现驱动程序估值器接口。
func (n NullBool) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return n.Bool, nil
}

// 空时间代表一个时间。时间可能是空的。
// NullTime实现了Scanner接口，因此
// 它可以用作扫描目标，类似于NullString。
type NullTime struct {
	Time  time.Time
	Valid bool // 如果时间不为空，则为真
}

// 扫描实现扫描仪接口。
func (n *NullTime) Scan(value any) error {
	if value == nil {
		n.Time, n.Valid = time.Time{}, false
		return nil
	}
	n.Valid = true
	return convertAssign(&n.Time, value)
}

// Value实现驱动程序估值器接口。
func (n NullTime) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return n.Time, nil
}

// Scanner是Scan使用的接口。
type Scanner interface {
	// 扫描从数据库驱动程序分配一个值。
	// 
	// src值将是以下类型之一：
	// 
	// int64 
	// float64 
	// bool 
	// /[]字节
	// 字符串
	// 时间。时间
	// nil-对于空值
	// 
	// 如果无法在不丢失信息的情况下存储值
	// 则应返回错误。
	// 
	// 像[]字节这样的引用类型只在下次调用扫描
	// 之前有效，不应保留。它们的基本内存由驾驶员拥有。
	// 如果需要保留，请在下次调用扫描之前复制它们的值。
	Scan(src any) error
}

// Out可用于从存储过程中检索输出值参数。不是所有的驱动程序和数据库都支持输出值参数。
// 
// 示例用法：
// 
// /var outArg string 
// ，err:=db。ExecContext（ctx，“ProcName”，sql.Named（“Arg1”，sql.Out{Dest:&outArg}））
type Out struct {
	_Named_Fields_Required struct{}

	// Dest是一个指针，指向将被设置为
	// 存储过程的输出参数的结果的值。
	Dest any

	// In表示该参数是否为INOUT参数。如果是这样，存储的
	// 过程的输入值就是Dest指针的解引用值，然后用
	// 替换为输出值。
	In bool
}

// 当QueryRow不返回
// 行时，通过扫描返回ErrNoRows。在这种情况下，QueryRow返回一个占位符*行值，
// 将此错误推迟到扫描。
var ErrNoRows = errors.New("sql: no rows in result set")

// DB是一个数据库句柄，表示零个或多个
// 基础连接的池。多个
// goroutines同时使用是安全的。
// 
// sql包自动创建和释放连接；它还维护空闲连接的空闲池。如果数据库有
// 每个连接状态的概念，则可以在事务（Tx）或连接（Conn）中可靠地观察到这种状态。一次。调用Begin时，返回的Tx被绑定到单个连接。一旦对事务调用了Commit或
// Rollback，该事务的
// 连接将返回到DB的空闲连接池。池大小
// 可使用SetMaxIdlecons进行控制。
type DB struct {
	// 仅限原子访问。在struct顶部，以防止在32位平台上错误对齐
	// 。时间的类型。期间
	waitDuration int64 // 等待新连接的总时间。

	connector driver.Connector
	// numClosed是一个原子计数器，它表示关闭的连接总数。Stmt。openStmt在清理关闭的
	// Stmt中的连接之前检查它。css。
	numClosed uint64

	mu           sync.Mutex    // 保护以下字段
	freeConn     []*driverConn // 返回的从最旧到最新的自由连接
	connRequests map[uint64]chan connRequest
	nextRequest  uint64 // 在请求中使用的下一个密钥。
	numOpen      int    // 打开和挂起的打开连接数
	// 用于表示需要新连接
	// 运行ConnectionOpen（）的goroutine在这个chan上读取，
	// 可能是OpenNewConnections在chan上发送（每个需要的连接发送一次）
	// 它在db期间关闭。Close（）。关闭通知连接开放者
	// goroutine退出。
	openerCh          chan struct{}
	closed            bool
	dep               map[finalCloser]depSet
	lastPut           map[*driverConn]string // ；只调试
	maxIdleCount      int                    // 零表示默认MaxIdlecons；负表示0 
	maxOpen           int                    // <=0表示无限
	maxLifetime       time.Duration          // 连接可重复使用的最长时间
	maxIdleTime       time.Duration          // 连接关闭前空闲的最长时间
	cleanerCh         chan struct{}
	waitCount         int64 // 等待的连接总数。
	maxIdleClosed     int64 // 由于空闲计数而关闭的连接总数。
	maxIdleTimeClosed int64 // 由于空闲时间而关闭的连接总数。
	maxLifetimeClosed int64 // 由于最大连接生存期限制而关闭的连接总数。

	stop func() // 停止取消连接开启器。
}

// connReuseStrategy决定（*DB）的方式。conn返回数据库连接。
type connReuseStrategy uint8

const (
	// alwaysNewConn强制与数据库建立新连接。
	alwaysNewConn connReuseStrategy = iota
	// cachedOrNewConn返回一个缓存的连接（如果可用），否则等待
	// 。
	cachedOrNewConn
)

// driverConn包装一个驱动程序。所有进入Conn的调用（包括对
// 接口的任何调用，如对Tx、Stmt、
// 结果、行的调用）
type driverConn struct {
	db        *DB
	createdAt time.Time

	sync.Mutex  // 
	ci          driver.Conn
	needReset   bool // 连接会话在使用前应重置，如果为真，则应使用带互斥锁的Conn。
	closed      bool
	finalClosed bool // ci。Close被称为
	openStmt    map[*driverStmt]bool

	// 由db保护。mu 
	inUse      bool
	returnedAt time.Time // 创建或返回连接的时间。
	onPut      []func()  // 下一次返回conn时运行的代码（保留db.mu）
	dbmuClosed bool      // 与关闭的代码相同，但由db保护。mu，对于RemoveClosedMTLocked 
}

func (dc *driverConn) releaseConn(err error) {
	dc.db.putConn(dc, err, true)
}

func (dc *driverConn) removeOpenStmt(ds *driverStmt) {
	dc.Lock()
	defer dc.Unlock()
	delete(dc.openStmt, ds)
}

func (dc *driverConn) expired(timeout time.Duration) bool {
	if timeout <= 0 {
		return false
	}
	return dc.createdAt.Add(timeout).Before(nowFunc())
}

// resetSession，检查驱动程序连接是否需要重置
// 会话，如果需要，将其重置。
func (dc *driverConn) resetSession(ctx context.Context) error {
	dc.Lock()
	defer dc.Unlock()

	if !dc.needReset {
		return nil
	}
	if cr, ok := dc.ci.(driver.SessionResetter); ok {
		return cr.ResetSession(ctx)
	}
	return nil
}

// validateConnection检查连接是否有效，并且
// 是否仍然可以使用。如果需要，它还会将会话标记为重置。
func (dc *driverConn) validateConnection(needsReset bool) bool {
	dc.Lock()
	defer dc.Unlock()

	if needsReset {
		dc.needReset = true
	}
	if cv, ok := dc.ci.(driver.Validator); ok {
		return cv.IsValid()
	}
	return true
}

// prepareLocked准备dc上的查询。当cg==nil时，dc必须跟踪
// 池中准备好的语句。
func (dc *driverConn) prepareLocked(ctx context.Context, cg stmtConnGrabber, query string) (*driverStmt, error) {
	si, err := ctxDriverPrepare(ctx, dc.ci, query)
	if err != nil {
		return nil, err
	}
	ds := &driverStmt{Locker: dc, si: si}

	// 如果只有一个连接抓取程序，则无需管理打开的语句。
	if cg != nil {
		return ds, nil
	}

	// 跟踪每个driverConn的open语句，以便我们可以在关闭conn之前关闭它们。
	// 
	// 包装所有驱动程序。Stmt是*driverStmt，以确保它们只关闭一次。
	if dc.openStmt == nil {
		dc.openStmt = make(map[*driverStmt]bool)
	}
	dc.openStmt[ds] = true
	return ds, nil
}

// dc。db的互斥被保持。
func (dc *driverConn) closeDBLocked() func() error {
	dc.Lock()
	defer dc.Unlock()
	if dc.closed {
		return func() error { return errors.New("sql: duplicate driverConn close") }
	}
	dc.closed = true
	return dc.db.removeDepLocked(dc, dc)
}

func (dc *driverConn) Close() error {
	dc.Lock()
	if dc.closed {
		dc.Unlock()
		return errors.New("sql: duplicate driverConn close")
	}
	dc.closed = true
	dc.Unlock() // 不延迟；removeDep finalClose呼叫可能需要锁定

	// 现在需要保留dc的更新。穆。锁
	dc.db.mu.Lock()
	dc.dbmuClosed = true
	fn := dc.db.removeDepLocked(dc, dc)
	dc.db.mu.Unlock()
	return fn()
}

func (dc *driverConn) finalClose() error {
	var err error

	// 每个*驱动器TMT都有一个dc锁。在每个stmt上调用close之前，从dc 
	// 复制列表。
	var openStmt []*driverStmt
	withLock(dc, func() {
		openStmt = make([]*driverStmt, 0, len(dc.openStmt))
		for ds := range dc.openStmt {
			openStmt = append(openStmt, ds)
		}
		dc.openStmt = nil
	})
	for _, ds := range openStmt {
		ds.Close()
	}
	withLock(dc, func() {
		dc.finalClosed = true
		err = dc.ci.Close()
		dc.ci = nil
	})

	dc.db.mu.Lock()
	dc.db.numOpen--
	dc.db.maybeOpenNewConnections()
	dc.db.mu.Unlock()

	atomic.AddUint64(&dc.db.numClosed, 1)
	return err
}

// driverStmt关联一个驱动程序。Stmt与它来自的
// /*driverConn一起使用，因此driverConn的锁可以在通话过程中保持
// 。
type driverStmt struct {
	sync.Locker // driverConn 
	si          driver.Stmt
	closed      bool
	closeErr    error // 上一次关闭调用的返回值
}

// 关闭驱动程序。Stmt只关闭一次，并且始终返回相同的
// 结果。
func (ds *driverStmt) Close() error {
	ds.Lock()
	defer ds.Unlock()
	if ds.closed {
		return ds.closeErr
	}
	ds.closed = true
	ds.closeErr = ds.si.Close()
	return ds.closeErr
}

// depSet是finalCloser的突出依赖项
type depSet map[any]bool // true bools集

// finalCloser接口由（*DB）使用。addDep和相关
// 依赖引用计数。
type finalCloser interface {
	// 当对象的引用计数
	// 变为零时，调用finalClose。（*DB）。mu在通话时没有被扣住。
	finalClose() error
}

// addDep注意到x现在依赖于dep，在用removeDep删除x的所有依赖项之前，不会调用x的finalClose。
func (db *DB) addDep(x finalCloser, dep any) {
	db.mu.Lock()
	defer db.mu.Unlock()
	db.addDepLocked(x, dep)
}

func (db *DB) addDepLocked(x finalCloser, dep any) {
	if db.dep == nil {
		db.dep = make(map[finalCloser]depSet)
	}
	xdep := db.dep[x]
	if xdep == nil {
		xdep = make(depSet)
		db.dep[x] = xdep
	}
	xdep[dep] = true
}

// removeDep注意到x不再依赖dep.
// 如果x仍然有依赖项，则返回nil。
// 如果x不再具有任何依赖项，则将调用其finalClose方法
// 并返回其错误值。
func (db *DB) removeDep(x finalCloser, dep any) error {
	db.mu.Lock()
	fn := db.removeDepLocked(x, dep)
	db.mu.Unlock()
	return fn()
}

func (db *DB) removeDepLocked(x finalCloser, dep any) func() error {

	xdep, ok := db.dep[x]
	if !ok {
		panic(fmt.Sprintf("unpaired removeDep: no deps for %T", x))
	}

	l0 := len(xdep)
	delete(xdep, dep)

	switch len(xdep) {
	case l0:
		// 未删除任何内容。不应该发生。
		panic(fmt.Sprintf("unpaired removeDep: no %T dep on %T", dep, x))
	case 0:
		// 不再依赖。
		delete(db.dep, x)
		return x.finalClose
	default:
		// 依赖关系仍然存在。
		return func() error { return nil }
	}
}

// 这是ConnectionOpen请求chan（DB.openerCh）的大小。
// 该值应大于用于db的最大典型值
// 值。maxOpen。如果maxOpen明显大于
// connectionRequestQueueSize，则所有对*DB 
// 的调用都可能被阻塞，直到ConnectionOpen能够满足积压的请求。
var connectionRequestQueueSize = 1000000

type dsnConnector struct {
	dsn    string
	driver driver.Driver
}

func (t dsnConnector) Connect(_ context.Context) (driver.Conn, error) {
	return t.driver.Open(t.dsn)
}

func (t dsnConnector) Driver() driver.Driver {
	return t.driver
}

// OpenDB使用连接器打开数据库，允许驱动程序绕过基于字符串的数据源名称。
// 
// 大多数用户将通过特定于驱动程序的连接打开数据库
// 返回*DB的helper函数。Go标准库中不包含数据库驱动程序
// 。看见https:
// 第三方驱动程序列表。
// 
// OpenDB可能只验证其参数，而不创建
// 到数据库的连接。要验证数据源名称是否有效，请调用
// Ping。
// 
// 返回的数据库可以安全地供多个Goroutine并发使用
// 并维护自己的空闲连接池。因此，OpenDB 
// 函数只需调用一次。几乎没有必要关闭数据库。
func OpenDB(c driver.Connector) *DB {
	ctx, cancel := context.WithCancel(context.Background())
	db := &DB{
		connector:    c,
		openerCh:     make(chan struct{}, connectionRequestQueueSize),
		lastPut:      make(map[*driverConn]string),
		connRequests: make(map[uint64]chan connRequest),
		stop:         cancel,
	}

	go db.connectionOpener(ctx)

	return db
}

// 打开一个由其数据库驱动程序名和
// 特定于驱动程序的数据源名指定的数据库，通常至少包含一个
// 数据库名和连接信息。
// 
// 大多数用户将通过特定于驱动程序的连接打开数据库
// 返回*DB的帮助函数。Go标准库中不包含数据库驱动程序
// 。看见https:
// 第三方驱动程序列表。
// 
// Open可能只验证其参数，而不创建与数据库的连接。要验证数据源名称是否有效，请调用
// Ping。
// 
// 返回的数据库对于多个Goroutine并发使用是安全的
// 并维护自己的空闲连接池。因此，只需调用一次Open 
// 函数。几乎没有必要关闭数据库。
func Open(driverName, dataSourceName string) (*DB, error) {
	driversMu.RLock()
	driveri, ok := drivers[driverName]
	driversMu.RUnlock()
	if !ok {
		return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
	}

	if driverCtx, ok := driveri.(driver.DriverContext); ok {
		connector, err := driverCtx.OpenConnector(dataSourceName)
		if err != nil {
			return nil, err
		}
		return OpenDB(connector), nil
	}

	return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}

func (db *DB) pingDC(ctx context.Context, dc *driverConn, release func(error)) error {
	var err error
	if pinger, ok := dc.ci.(driver.Pinger); ok {
		withLock(dc, func() {
			err = pinger.Ping(ctx)
		})
	}
	release(err)
	return err
}

// PingContext验证与数据库的连接是否仍处于活动状态，
// 必要时建立连接。
func (db *DB) PingContext(ctx context.Context) error {
	var dc *driverConn
	var err error
	var isBadConn bool
	for i := 0; i < maxBadConnRetries; i++ {
		dc, err = db.conn(ctx, cachedOrNewConn)
		isBadConn = errors.Is(err, driver.ErrBadConn)
		if !isBadConn {
			break
		}
	}
	if isBadConn {
		dc, err = db.conn(ctx, alwaysNewConn)
	}
	if err != nil {
		return err
	}

	return db.pingDC(ctx, dc, dc.releaseConn)
}

// Ping验证与数据库的连接是否仍然有效，
// 如有必要，建立连接。
// 
// Ping使用上下文。内部背景；要指定上下文，请使用
// PingContext。
func (db *DB) Ping() error {
	return db.PingContext(context.Background())
}

// Close关闭数据库并阻止新查询启动。
// 关闭然后等待服务器
// 上已开始处理的所有查询完成。
// 
// 关闭数据库是很少见的，因为数据库句柄应该是
// 长期存在的，并且在许多Goroutine之间共享。
func (db *DB) Close() error {
	db.mu.Lock()
	if db.closed { // 制作数据库。Close幂等式
		db.mu.Unlock()
		return nil
	}
	if db.cleanerCh != nil {
		close(db.cleanerCh)
	}
	var err error
	fns := make([]func() error, 0, len(db.freeConn))
	for _, dc := range db.freeConn {
		fns = append(fns, dc.closeDBLocked())
	}
	db.freeConn = nil
	db.closed = true
	for _, req := range db.connRequests {
		close(req)
	}
	db.mu.Unlock()
	for _, fn := range fns {
		err1 := fn()
		if err1 != nil {
			err = err1
		}
	}
	db.stop()
	if c, ok := db.connector.(io.Closer); ok {
		err1 := c.Close()
		if err1 != nil {
			err = err1
		}
	}
	return err
}

const defaultMaxIdleConns = 2

func (db *DB) maxIdleConnsLocked() int {
	n := db.maxIdleCount
	switch {
	case n == 0:
		// TODO（bradfitz）：如果支持，向驱动程序询问其默认首选项
		return defaultMaxIdleConns
	case n < 0:
		return 0
	default:
		return n
	}
}

func (db *DB) shortestIdleTimeLocked() time.Duration {
	if db.maxIdleTime <= 0 {
		return db.maxLifetime
	}
	if db.maxLifetime <= 0 {
		return db.maxIdleTime
	}

	min := db.maxIdleTime
	if min > db.maxLifetime {
		min = db.maxLifetime
	}
	return min
}

// SetMaxidlecons设置空闲
// 连接池中的最大连接数。
// 
// 如果MaxOpenConns大于0但小于新的MaxIdleConns，
// 则新的MaxIdleConns将减少以匹配MaxOpenConns限制。
// 
// 如果n<=0，则不保留空闲连接。
// 
// 默认最大空闲连接数当前为2。这可能会在
// 的未来版本中发生变化。
func (db *DB) SetMaxIdleConns(n int) {
	db.mu.Lock()
	if n > 0 {
		db.maxIdleCount = n
	} else {
		// 没有空闲连接。
		db.maxIdleCount = -1
	}
	// 确保maxIdle不超过maxOpen 
	if db.maxOpen > 0 && db.maxIdleConnsLocked() > db.maxOpen {
		db.maxIdleCount = db.maxOpen
	}
	var closing []*driverConn
	idleCount := len(db.freeConn)
	maxIdle := db.maxIdleConnsLocked()
	if idleCount > maxIdle {
		closing = db.freeConn[maxIdle:]
		db.freeConn = db.freeConn[:maxIdle]
	}
	db.maxIdleClosed += int64(len(closing))
	db.mu.Unlock()
	for _, c := range closing {
		c.Close()
	}
}

// SetMaxOpenConns设置与数据库的最大打开连接数。
// 
// 如果MaxIdleConns大于0且新的MaxOpenConns小于
// MaxIdleConns，则MaxIdleConns将减少，以匹配新的
// MaxOpenConns限制。
// 
// 如果n<=0，则对打开的连接数没有限制。
// 默认值为0（无限制）。
func (db *DB) SetMaxOpenConns(n int) {
	db.mu.Lock()
	db.maxOpen = n
	if n < 0 {
		db.maxOpen = 0
	}
	syncMaxIdle := db.maxOpen > 0 && db.maxIdleConnsLocked() > db.maxOpen
	db.mu.Unlock()
	if syncMaxIdle {
		db.SetMaxIdleConns(n)
	}
}

// SetConnMaxLifetime设置连接可重复使用的最大时间。
// 
// 过期的连接在重新使用之前可能会被延迟关闭。
// 
// 如果d<=0，则连接不会因连接的使用年限而关闭。
func (db *DB) SetConnMaxLifetime(d time.Duration) {
	if d < 0 {
		d = 0
	}
	db.mu.Lock()
	// 当寿命缩短时，请醒来。
	if d > 0 && d < db.maxLifetime && db.cleanerCh != nil {
		select {
		case db.cleanerCh <- struct{}{}:
		default:
		}
	}
	db.maxLifetime = d
	db.startCleanerLocked()
	db.mu.Unlock()
}

// SetConnMaxIdleTime设置连接空闲的最长时间。
// 
// 过期的连接在重新使用之前可能会被延迟关闭。
// 
// 如果d<=0，则由于连接的空闲时间，连接不会关闭。
func (db *DB) SetConnMaxIdleTime(d time.Duration) {
	if d < 0 {
		d = 0
	}
	db.mu.Lock()
	defer db.mu.Unlock()

	// 空闲时间缩短时唤醒清洁器。
	if d > 0 && d < db.maxIdleTime && db.cleanerCh != nil {
		select {
		case db.cleanerCh <- struct{}{}:
		default:
		}
	}
	db.maxIdleTime = d
	db.startCleanerLocked()
}

// 如果需要，startCleanerLocked将启动connectionCleaner。
func (db *DB) startCleanerLocked() {
	if (db.maxLifetime > 0 || db.maxIdleTime > 0) && db.numOpen > 0 && db.cleanerCh == nil {
		db.cleanerCh = make(chan struct{}, 1)
		go db.connectionCleaner(db.shortestIdleTimeLocked())
	}
}

func (db *DB) connectionCleaner(d time.Duration) {
	const minInterval = time.Second

	if d < minInterval {
		d = minInterval
	}
	t := time.NewTimer(d)

	for {
		select {
		case <-t.C:
		case <-db.cleanerCh: // maxLifetime已更改或数据库已关闭。
		}

		db.mu.Lock()

		d = db.shortestIdleTimeLocked()
		if db.closed || db.numOpen == 0 || d <= 0 {
			db.cleanerCh = nil
			db.mu.Unlock()
			return
		}

		d, closing := db.connectionCleanerRunLocked(d)
		db.mu.Unlock()
		for _, c := range closing {
			c.Close()
		}

		if d < minInterval {
			d = minInterval
		}

		if !t.Stop() {
			select {
			case <-t.C:
			default:
			}
		}
		t.Reset(d)
	}
}

// ConnectionCleanerUnlocked从
// freeConn中删除应关闭的连接，并将其连同更新的持续时间返回给下一次检查
// 如果需要进行更快速的检查以确保正确检查连接。
func (db *DB) connectionCleanerRunLocked(d time.Duration) (time.Duration, []*driverConn) {
	var idleClosing int64
	var closing []*driverConn
	if db.maxIdleTime > 0 {
		// 因为freeConn是通过退货流程
		// 以相反的顺序订购的，以尽量减少所需的工作量。
		idleSince := nowFunc().Add(-db.maxIdleTime)
		last := len(db.freeConn) - 1
		for i := last; i >= 0; i-- {
			c := db.freeConn[i]
			if c.returnedAt.Before(idleSince) {
				i++
				closing = db.freeConn[:i:i]
				db.freeConn = db.freeConn[i:]
				idleClosing = int64(len(closing))
				db.maxIdleTimeClosed += idleClosing
				break
			}
		}

		if len(db.freeConn) > 0 {
			c := db.freeConn[0]
			if d2 := c.returnedAt.Sub(idleSince); d2 < d {
				// 确保尽快清理空闲连接。
				d = d2
			}
		}
	}

	if db.maxLifetime > 0 {
		expiredSince := nowFunc().Add(-db.maxLifetime)
		for i := 0; i < len(db.freeConn); i++ {
			c := db.freeConn[i]
			if c.createdAt.Before(expiredSince) {
				closing = append(closing, c)

				last := len(db.freeConn) - 1
				// 按顺序使用慢速删除，以确保首先以最少的空闲时间重用连接。
				copy(db.freeConn[i:], db.freeConn[i+1:])
				db.freeConn[last] = nil
				db.freeConn = db.freeConn[:last]
				i--
			} else if d2 := c.createdAt.Sub(expiredSince); d2 < d {
				// 更新我们的下一个截止日期d，以防止连接在freeConn上过期。
				// DBStats包含数据库统计信息。
				d = d2
			}
		}
		db.maxLifetimeClosed += int64(len(closing)) - idleClosing
	}

	return d, closing
}

type DBStats struct {
	MaxOpenConnections int // 打开到数据库的最大连接数。

	// 池状态
	OpenConnections int // 正在使用和空闲的已建立连接数。
	InUse           int // 当前正在使用的连接数。
	Idle            int // 空闲连接数。

	// 计数器
	WaitCount         int64         // 等待的连接总数。
	WaitDuration      time.Duration // 等待新连接被阻止的总时间。
	MaxIdleClosed     int64         // 由于SetMaxIdlecons而关闭的连接总数。
	MaxIdleTimeClosed int64         // 由于SetConnMaxIdleTime而关闭的连接总数。
	MaxLifetimeClosed int64         // 由于SetConnMaxLifetime而关闭的连接总数。
}

// Stats返回数据库统计信息。
func (db *DB) Stats() DBStats {
	wait := atomic.LoadInt64(&db.waitDuration)

	db.mu.Lock()
	defer db.mu.Unlock()

	stats := DBStats{
		MaxOpenConnections: db.maxOpen,

		Idle:            len(db.freeConn),
		OpenConnections: db.numOpen,
		InUse:           db.numOpen - len(db.freeConn),

		WaitCount:         db.waitCount,
		WaitDuration:      time.Duration(wait),
		MaxIdleClosed:     db.maxIdleClosed,
		MaxIdleTimeClosed: db.maxIdleTimeClosed,
		MaxLifetimeClosed: db.maxLifetimeClosed,
	}
	return stats
}

// db。穆被锁上了。
// 如果有连接请求，但尚未达到连接限制，
// 然后告诉连接开启者打开新的连接。
func (db *DB) maybeOpenNewConnections() {
	numRequests := len(db.connRequests)
	if db.maxOpen > 0 {
		numCanOpen := db.maxOpen - db.numOpen
		if numRequests > numCanOpen {
			numRequests = numCanOpen
		}
	}
	for numRequests > 0 {
		db.numOpen++ // 乐观地说，
		numRequests--
		if db.closed {
			return
		}
		db.openerCh <- struct{}{}
	}
}

// 在单独的goroutine中运行，在请求时打开新的连接。
func (db *DB) connectionOpener(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		case <-db.openerCh:
			db.openNewConnection(ctx)
		}
	}
}

// 打开一个新连接
func (db *DB) openNewConnection(ctx context.Context) {
	// 可能是OpenNewConnections已经执行了db。numOpen++在数据库上发送
	// 之前。开场白。此函数必须执行db。numOpen——如果
	// 连接失败或在返回前关闭。
	ci, err := db.connector.Connect(ctx)
	db.mu.Lock()
	defer db.mu.Unlock()
	if db.closed {
		if err == nil {
			ci.Close()
		}
		db.numOpen--
		return
	}
	if err != nil {
		db.numOpen--
		db.putConnDBLocked(nil, err)
		db.maybeOpenNewConnections()
		return
	}
	dc := &driverConn{
		db:         db,
		createdAt:  nowFunc(),
		returnedAt: nowFunc(),
		ci:         ci,
	}
	if db.putConnDBLocked(dc, err) {
		db.addDepLocked(dc, dc)
	} else {
		db.numOpen--
		ci.Close()
	}
}

// connRequest表示一个新连接请求
// 当没有可用的空闲连接时，DB。conn将创建
// 一个新的connRequest并将其放在db上。康纳的请求列表。
type connRequest struct {
	conn *driverConn
	err  error
}

var errDBClosed = errors.New("sql: database is closed")

// nextRequestKeyLocked返回下一个连接请求密钥。
// 假设nextRequest不会溢出。
func (db *DB) nextRequestKeyLocked() uint64 {
	next := db.nextRequest
	db.nextRequest++
	return next
}

// conn返回一个新打开或缓存的*driverConn。
func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) {
	db.mu.Lock()
	if db.closed {
		db.mu.Unlock()
		return nil, errDBClosed
	}
	// 检查上下文是否过期。
	select {
	default:
	case <-ctx.Done():
		db.mu.Unlock()
		return nil, ctx.Err()
	}
	lifetime := db.maxLifetime

	// 如果可能的话，更喜欢免费连接。
	last := len(db.freeConn) - 1
	if strategy == cachedOrNewConn && last >= 0 {
		// 重新使用空闲时间最低的连接，以便我们可以尽快关闭保持空闲的
		// 连接。
		conn := db.freeConn[last]
		db.freeConn = db.freeConn[:last]
		conn.inUse = true
		if conn.expired(lifetime) {
			db.maxLifetimeClosed++
			db.mu.Unlock()
			conn.Close()
			return nil, driver.ErrBadConn
		}
		db.mu.Unlock()

		// 如果需要，请重置会话。
		if err := conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) {
			conn.Close()
			return nil, err
		}

		return conn, nil
	}

	// 没有免费连接，或者我们被要求不要使用。如果
	// 不允许我们打开更多连接，请发出请求并等待。
	if db.maxOpen > 0 && db.numOpen >= db.maxOpen {
		// 创建请求通道。对其进行缓冲，以便
		// ConnectionOpen在等待读取req时不会阻塞。
		req := make(chan connRequest, 1)
		reqKey := db.nextRequestKeyLocked()
		db.connRequests[reqKey] = req
		db.waitCount++
		db.mu.Unlock()

		waitStart := nowFunc()

		// 将连接请求与上下文超时。
		select {
		case <-ctx.Done():
			// 删除连接请求，并确保删除后未向其发送任何值。
			db.mu.Lock()
			delete(db.connRequests, reqKey)
			db.mu.Unlock()

			atomic.AddInt64(&db.waitDuration, int64(time.Since(waitStart)))

			select {
			default:
			case ret, ok := <-req:
				if ok && ret.conn != nil {
					db.putConn(ret.conn, ret.err, false)
				}
			}
			return nil, ctx.Err()
		case ret, ok := <-req:
			atomic.AddInt64(&db.waitDuration, int64(time.Since(waitStart)))

			if !ok {
				return nil, errDBClosed
			}
			// 仅在策略为cachedOrNewConns时检查连接是否过期。
			// 如果我们需要一个新的连接，只需重新使用该连接，而不必在到期时查看
			// 即可。如果过期，将
			// 放回连接池时将对其进行检查。
			// 这将优先考虑与客户机建立有效连接，而不是提供确切的连接
			// 生命周期，无论如何都可能在这一点之后到期。
			if strategy == cachedOrNewConn && ret.err == nil && ret.conn.expired(lifetime) {
				db.mu.Lock()
				db.maxLifetimeClosed++
				db.mu.Unlock()
				ret.conn.Close()
				return nil, driver.ErrBadConn
			}
			if ret.conn == nil {
				return nil, ret.err
			}

			// 如果需要，请重置会话。
			if err := ret.conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) {
				ret.conn.Close()
				return nil, err
			}
			return ret.conn, ret.err
		}
	}

	db.numOpen++ // 乐观地
	db.mu.Unlock()
	ci, err := db.connector.Connect(ctx)
	if err != nil {
		db.mu.Lock()
		db.numOpen-- // 纠正了之前的乐观态度
		db.maybeOpenNewConnections()
		db.mu.Unlock()
		return nil, err
	}
	db.mu.Lock()
	dc := &driverConn{
		db:         db,
		createdAt:  nowFunc(),
		returnedAt: nowFunc(),
		ci:         ci,
		inUse:      true,
	}
	db.addDepLocked(dc, dc)
	db.mu.Unlock()
	return dc, nil
}

// PutconHook是一个用于测试的钩子。
var putConnHook func(*DB, *driverConn)

// noteUnusedDrivers声明指出ds不再使用，应尽可能关闭（当c下次不使用时），除非c已关闭。
func (db *DB) noteUnusedDriverStatement(c *driverConn, ds *driverStmt) {
	db.mu.Lock()
	defer db.mu.Unlock()
	if c.inUse {
		c.onPut = append(c.onPut, func() {
			ds.Close()
		})
	} else {
		c.Lock()
		fc := c.finalClosed
		c.Unlock()
		if !fc {
			ds.Close()
		}
	}
}

// debugGetPut确定getConn&putConn调用的堆栈跟踪
// 是否会因更详细的崩溃而返回。
const debugGetPut = false

// putConn向数据库的空闲池添加一个连接。
// err是此连接上发生的最后一个错误。
func (db *DB) putConn(dc *driverConn, err error, resetSession bool) {
	if !errors.Is(err, driver.ErrBadConn) {
		if !dc.validateConnection(resetSession) {
			err = driver.ErrBadConn
		}
	}
	db.mu.Lock()
	if !dc.inUse {
		db.mu.Unlock()
		if debugGetPut {
			fmt.Printf("putConn(%v) DUPLICATE was: %s\n\nPREVIOUS was: %s", dc, stack(), db.lastPut[dc])
		}
		panic("sql: connection returned that was never out")
	}

	if !errors.Is(err, driver.ErrBadConn) && dc.expired(db.maxLifetime) {
		db.maxLifetimeClosed++
		err = driver.ErrBadConn
	}
	if debugGetPut {
		db.lastPut[dc] = stack()
	}
	dc.inUse = false
	dc.returnedAt = nowFunc()

	for _, fn := range dc.onPut {
		fn()
	}
	dc.onPut = nil

	if errors.Is(err, driver.ErrBadConn) {
		// 不要重复使用坏连接。
		// 由于连接被认为是坏的，正在被丢弃，请将其视为已关闭。不要在这里减少开放计数，finalClose会处理好的。
		db.maybeOpenNewConnections()
		db.mu.Unlock()
		dc.Close()
		return
	}
	if putConnHook != nil {
		putConnHook(db, dc)
	}
	added := db.putConnDBLocked(dc, nil)
	db.mu.Unlock()

	if !added {
		dc.Close()
		return
	}
}

// 满足连接请求或将driverConn放入空闲池，并返回true 
// 或返回false。
// 如果存在连接请求，PutConndBlock将满足该请求；如果err==nil，PutConndBlock将
// 将*driverConn返回freeConn列表，并且不会超过空闲
// 连接限制。
// 如果出错！=nil，忽略dc的值。
// 如果err==nil，那么dc不能等于nil。
// 如果connRequest得到满足，或者*driverConn被放置在
// freeConn列表中，则返回true，否则返回false。
func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
	if db.closed {
		return false
	}
	if db.maxOpen > 0 && db.numOpen > db.maxOpen {
		return false
	}
	if c := len(db.connRequests); c > 0 {
		var req chan connRequest
		var reqKey uint64
		for reqKey, req = range db.connRequests {
			break
		}
		delete(db.connRequests, reqKey) // 从挂起的请求中删除。
		if err == nil {
			dc.inUse = true
		}
		req <- connRequest{
			conn: dc,
			err:  err,
		}
		return true
	} else if err == nil && !db.closed {
		if db.maxIdleConnsLocked() > len(db.freeConn) {
			db.freeConn = append(db.freeConn, dc)
			db.startCleanerLocked()
			return true
		}
		db.maxIdleClosed++
	}
	return false
}

// maxBadConnRetries是驱动程序返回
// driver时的最大重试次数。ErrBadConn在强制打开新的
// 连接之前发出断开连接的信号。
const maxBadConnRetries = 2

// PrepareContext为以后的查询或执行创建准备好的语句。
// 从
// 返回的语句可以同时运行多个查询或执行。
// 当不再需要该语句时，调用方必须调用该语句的Close方法
// 。
// 
// 提供的上下文用于准备语句，而不是用于执行语句。
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
	var stmt *Stmt
	var err error
	var isBadConn bool
	for i := 0; i < maxBadConnRetries; i++ {
		stmt, err = db.prepare(ctx, query, cachedOrNewConn)
		isBadConn = errors.Is(err, driver.ErrBadConn)
		if !isBadConn {
			break
		}
	}
	if isBadConn {
		return db.prepare(ctx, query, alwaysNewConn)
	}
	return stmt, err
}

// Prepare为以后的查询或执行创建一条准备好的语句。
// 从
// 返回的语句可以同时运行多个查询或执行。
// 当不再需要该语句时，调用方必须调用该语句的Close方法
// 。
// 
// 准备使用上下文。内部背景；要指定上下文，请使用
// PrepareContext。
func (db *DB) Prepare(query string) (*Stmt, error) {
	return db.PrepareContext(context.Background(), query)
}

func (db *DB) prepare(ctx context.Context, query string, strategy connReuseStrategy) (*Stmt, error) {
	// TODO:检查数据库是否正确。驱动程序支持可选的
	// 驱动程序。Preparer接口并调用它，如果是，则调用
	// 否则我们将生成一个准备好的语句，将
	// 绑定到一个连接，并执行这个准备好的语句
	// 我们要么需要使用这个连接（如果它是免费的），要么
	// 获得一个新连接+重新准备+在那个连接上执行。
	dc, err := db.conn(ctx, strategy)
	if err != nil {
		return nil, err
	}
	return db.prepareDC(ctx, dc, dc.releaseConn, nil, query)
}

// prepareDC在返回之前准备对driverConn的查询并调用release。当cg==nil时，表示使用了连接池，当cg！=无仅使用单个驱动程序连接。
func (db *DB) prepareDC(ctx context.Context, dc *driverConn, release func(error), cg stmtConnGrabber, query string) (*Stmt, error) {
	var ds *driverStmt
	var err error
	defer func() {
		release(err)
	}()
	withLock(dc, func() {
		ds, err = dc.prepareLocked(ctx, cg, query)
	})
	if err != nil {
		return nil, err
	}
	stmt := &Stmt{
		db:    db,
		query: query,
		cg:    cg,
		cgds:  ds,
	}

	// 当cg==nil时，此语句需要跟踪各种
	// 连接，并记录对
	// 数据库的stmt依赖关系。
	if cg == nil {
		stmt.css = []connStmt{{dc, ds}}
		stmt.lastNumClosed = atomic.LoadUint64(&db.numClosed)
		db.addDep(stmt, stmt)
	}
	return stmt, nil
}

// ExecContext执行查询时不返回任何行。
// 参数用于查询中的任何占位符参数。
func (db *DB) ExecContext(ctx context.Context, query string, args ...any) (Result, error) {
	var res Result
	var err error
	var isBadConn bool
	for i := 0; i < maxBadConnRetries; i++ {
		res, err = db.exec(ctx, query, args, cachedOrNewConn)
		isBadConn = errors.Is(err, driver.ErrBadConn)
		if !isBadConn {
			break
		}
	}
	if isBadConn {
		return db.exec(ctx, query, args, alwaysNewConn)
	}
	return res, err
}

// Exec执行查询时不返回任何行。
// 参数用于查询中的任何占位符参数。
// 
// Exec使用上下文。内部背景；要指定上下文，请使用
// ExecContext。
func (db *DB) Exec(query string, args ...any) (Result, error) {
	return db.ExecContext(context.Background(), query, args...)
}

func (db *DB) exec(ctx context.Context, query string, args []any, strategy connReuseStrategy) (Result, error) {
	dc, err := db.conn(ctx, strategy)
	if err != nil {
		return nil, err
	}
	return db.execDC(ctx, dc, dc.releaseConn, query, args)
}

func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), query string, args []any) (res Result, err error) {
	defer func() {
		release(err)
	}()
	execerCtx, ok := dc.ci.(driver.ExecerContext)
	var execer driver.Execer
	if !ok {
		execer, ok = dc.ci.(driver.Execer)
	}
	if ok {
		var nvdargs []driver.NamedValue
		var resi driver.Result
		withLock(dc, func() {
			nvdargs, err = driverArgsConnLocked(dc.ci, nil, args)
			if err != nil {
				return
			}
			resi, err = ctxDriverExec(ctx, execerCtx, execer, query, nvdargs)
		})
		if err != driver.ErrSkip {
			if err != nil {
				return nil, err
			}
			return driverResult{dc, resi}, nil
		}
	}

	var si driver.Stmt
	withLock(dc, func() {
		si, err = ctxDriverPrepare(ctx, dc.ci, query)
	})
	if err != nil {
		return nil, err
	}
	ds := &driverStmt{Locker: dc, si: si}
	defer ds.Close()
	return resultFromStatement(ctx, dc.ci, ds, args...)
}

// QueryContext执行返回行的查询，通常是SELECT。
// 参数用于查询中的任何占位符参数。
func (db *DB) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error) {
	var rows *Rows
	var err error
	var isBadConn bool
	for i := 0; i < maxBadConnRetries; i++ {
		rows, err = db.query(ctx, query, args, cachedOrNewConn)
		isBadConn = errors.Is(err, driver.ErrBadConn)
		if !isBadConn {
			break
		}
	}
	if isBadConn {
		return db.query(ctx, query, args, alwaysNewConn)
	}
	return rows, err
}

// 查询执行返回行的查询，通常是SELECT。
// 参数用于查询中的任何占位符参数。
// 
// 查询使用上下文。内部背景；要指定上下文，请使用
// QueryContext。
func (db *DB) Query(query string, args ...any) (*Rows, error) {
	return db.QueryContext(context.Background(), query, args...)
}

func (db *DB) query(ctx context.Context, query string, args []any, strategy connReuseStrategy) (*Rows, error) {
	dc, err := db.conn(ctx, strategy)
	if err != nil {
		return nil, err
	}

	return db.queryDC(ctx, nil, dc, dc.releaseConn, query, args)
}

// queryDC对给定连接执行查询。
// 通过releaseConn函数释放连接。
// ctx上下文来自查询方法，txctx上下文来自
// 可选事务上下文。
func (db *DB) queryDC(ctx, txctx context.Context, dc *driverConn, releaseConn func(error), query string, args []any) (*Rows, error) {
	queryerCtx, ok := dc.ci.(driver.QueryerContext)
	var queryer driver.Queryer
	if !ok {
		queryer, ok = dc.ci.(driver.Queryer)
	}
	if ok {
		var nvdargs []driver.NamedValue
		var rowsi driver.Rows
		var err error
		withLock(dc, func() {
			nvdargs, err = driverArgsConnLocked(dc.ci, nil, args)
			if err != nil {
				return
			}
			rowsi, err = ctxDriverQuery(ctx, queryerCtx, queryer, query, nvdargs)
		})
		if err != driver.ErrSkip {
			if err != nil {
				releaseConn(err)
				return nil, err
			}
			// 注意：dc的所有权转移到*行，待释放
			// 使用releaseConn。
			rows := &Rows{
				dc:          dc,
				releaseConn: releaseConn,
				rowsi:       rowsi,
			}
			rows.initContextClose(ctx, txctx)
			return rows, nil
		}
	}

	var si driver.Stmt
	var err error
	withLock(dc, func() {
		si, err = ctxDriverPrepare(ctx, dc.ci, query)
	})
	if err != nil {
		releaseConn(err)
		return nil, err
	}

	ds := &driverStmt{Locker: dc, si: si}
	rowsi, err := rowsiFromStatement(ctx, dc.ci, ds, args...)
	if err != nil {
		ds.Close()
		releaseConn(err)
		return nil, err
	}

	// 注意：ci的所有权转移到*行，待释放
	// 使用releaseConn。
	rows := &Rows{
		dc:          dc,
		releaseConn: releaseConn,
		rowsi:       rowsi,
		closeStmt:   ds,
	}
	rows.initContextClose(ctx, txctx)
	return rows, nil
}

// QueryRowContext执行一个最多返回一行的查询。
// QueryRowContext始终返回非零值。错误被推迟到调用
// 行的扫描方法。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并丢弃剩余的
// 行。
func (db *DB) QueryRowContext(ctx context.Context, query string, args ...any) *Row {
	rows, err := db.QueryContext(ctx, query, args...)
	return &Row{rows: rows, err: err}
}

// QueryRow执行一个最多返回一行的查询。
// QueryRow始终返回非零值。错误被推迟到调用
// 行的扫描方法。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并丢弃剩余的
// 行。
// 
// QueryRow使用上下文。内部背景；要指定上下文，请使用
// QueryRowContext。zhong zhong defg
func (db *DB) QueryRow(query string, args ...any) *Row {
	return db.QueryRowContext(context.Background(), query, args...)
}

// 
// 在提交或回滚事务之前，将使用提供的上下文。
// 如果取消上下文，sql包将回滚
// 事务。如果提供给
// BeginTx的上下文被取消，Tx.Commit将返回一个错误。
// 
// 提供的TXO选项是可选的，如果应该使用默认值，则可能为零。
// 如果使用了驱动程序不支持的非默认隔离级别，
// 将返回一个错误。
func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
	var tx *Tx
	var err error
	var isBadConn bool
	for i := 0; i < maxBadConnRetries; i++ {
		tx, err = db.begin(ctx, opts, cachedOrNewConn)
		isBadConn = errors.Is(err, driver.ErrBadConn)
		if !isBadConn {
			break
		}
	}
	if isBadConn {
		return db.begin(ctx, opts, alwaysNewConn)
	}
	return tx, err
}

// Begin启动事务。默认隔离级别取决于
// 驱动程序。
// 
// Begin使用上下文。内部背景；要指定上下文，请使用
// BeginTx。
func (db *DB) Begin() (*Tx, error) {
	return db.BeginTx(context.Background(), nil)
}

func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStrategy) (tx *Tx, err error) {
	dc, err := db.conn(ctx, strategy)
	if err != nil {
		return nil, err
	}
	return db.beginDC(ctx, dc, dc.releaseConn, opts)
}

// beginDC启动事务。提供的dc必须有效且随时可用。
func (db *DB) beginDC(ctx context.Context, dc *driverConn, release func(error), opts *TxOptions) (tx *Tx, err error) {
	var txi driver.Tx
	keepConnOnRollback := false
	withLock(dc, func() {
		_, hasSessionResetter := dc.ci.(driver.SessionResetter)
		_, hasConnectionValidator := dc.ci.(driver.Validator)
		keepConnOnRollback = hasSessionResetter && hasConnectionValidator
		txi, err = ctxDriverBegin(ctx, opts, dc.ci)
	})
	if err != nil {
		release(err)
		return nil, err
	}

	// 将事务安排为在取消上下文时回滚。
	// 设置为true后，将调用Tx中的cancel函数。
	ctx, cancel := context.WithCancel(ctx)
	tx = &Tx{
		db:                 db,
		dc:                 dc,
		releaseConn:        release,
		txi:                txi,
		cancel:             cancel,
		keepConnOnRollback: keepConnOnRollback,
		ctx:                ctx,
	}
	go tx.awaitDone()
	return tx, nil
}

// Driver返回数据库的底层驱动程序。
func (db *DB) Driver() driver.Driver {
	return db.connector.Driver()
}

// 对已返回到连接池的连接执行的任何操作都会返回ErrConnDone。
var ErrConnDone = errors.New("sql: connection is already closed")

// Conn通过打开新连接或从连接池返回现有连接来返回单个连接。Conn将
// 阻塞，直到返回连接或取消ctx。
// 在同一个Conn上运行的查询将在同一个数据库会话中运行。
// 
// 每个Conn在被
// 调用Conn.Close后必须返回到数据库池。
func (db *DB) Conn(ctx context.Context) (*Conn, error) {
	var dc *driverConn
	var err error
	var isBadConn bool
	for i := 0; i < maxBadConnRetries; i++ {
		dc, err = db.conn(ctx, cachedOrNewConn)
		isBadConn = errors.Is(err, driver.ErrBadConn)
		if !isBadConn {
			break
		}
	}
	if isBadConn {
		dc, err = db.conn(ctx, alwaysNewConn)
	}
	if err != nil {
		return nil, err
	}

	conn := &Conn{
		db: db,
		dc: dc,
	}
	return conn, nil
}

type releaseConn func(error)

// Conn代表单个数据库连接，而不是数据库池
// 连接。更喜欢从数据库运行查询，除非有特定的
// 需要连续的单个数据库连接。
// 
// Conn必须调用Close以返回到数据库池的连接
// 并且可以与正在运行的查询同时执行此操作。
// 
// 在调用Close后，
// 连接上的所有操作都会失败，错误已完成。
type Conn struct {
	db *DB

	// closemu阻止连接关闭，而
	// 是一个活动查询。在查询
	// /期间，它被保存以供阅读，在关闭期间，它被专门保存。
	closemu sync.RWMutex

	// dc在关闭前一直是所有的，此时
	// 它将返回到连接池。
	dc *driverConn

	// 在关闭时，从0到1的转换只完成了一次。
	// 一旦完成，所有操作都会失败，并返回ErrConnDone。
	// 检查值时对值使用原子操作。
	done int32
}

// grabConn需要一个上下文来实现stmtConnGrabber 
// 但不使用上下文。
func (c *Conn) grabConn(context.Context) (*driverConn, releaseConn, error) {
	if atomic.LoadInt32(&c.done) != 0 {
		return nil, nil, ErrConnDone
	}
	c.closemu.RLock()
	return c.dc, c.closemuRUnlockCondReleaseConn, nil
}

// PingContext验证与数据库的连接是否仍然有效。
func (c *Conn) PingContext(ctx context.Context) error {
	dc, release, err := c.grabConn(ctx)
	if err != nil {
		return err
	}
	return c.db.pingDC(ctx, dc, release)
}

// ExecContext执行查询时不返回任何行。
// 参数用于查询中的任何占位符参数。
func (c *Conn) ExecContext(ctx context.Context, query string, args ...any) (Result, error) {
	dc, release, err := c.grabConn(ctx)
	if err != nil {
		return nil, err
	}
	return c.db.execDC(ctx, dc, release, query, args)
}

// QueryContext执行返回行的查询，通常是SELECT。
// 参数用于查询中的任何占位符参数。
func (c *Conn) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error) {
	dc, release, err := c.grabConn(ctx)
	if err != nil {
		return nil, err
	}
	return c.db.queryDC(ctx, nil, dc, release, query, args)
}

// QueryRowContext执行一个最多返回一行的查询。
// QueryRowContext始终返回非零值。错误延迟到
// 调用行的扫描方法。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并放弃
// 其余的行。
func (c *Conn) QueryRowContext(ctx context.Context, query string, args ...any) *Row {
	rows, err := c.QueryContext(ctx, query, args...)
	return &Row{rows: rows, err: err}
}

// PrepareContext为以后的查询或执行创建准备好的语句。
// 从
// 返回的语句可以同时运行多个查询或执行。
// 当不再需要该语句时，调用者必须调用该语句的Close方法
// 。
// 
// 提供的上下文用于准备语句，而不是用于执行语句。
func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
	dc, release, err := c.grabConn(ctx)
	if err != nil {
		return nil, err
	}
	return c.db.prepareDC(ctx, dc, release, c, query)
}

// Raw执行f，为
// f的持续时间公开基础驱动程序连接。driverConn不能在f之外使用。
// 
// 一旦f返回且err不是驱动程序。ErrBadConn，在调用Conn.Close之前，Conn将继续可用
// 。
func (c *Conn) Raw(f func(driverConn any) error) (err error) {
	var dc *driverConn
	var release releaseConn

	// grabConn使用上下文来实现stmtConnGrabber，但未使用上下文。
	dc, release, err = c.grabConn(nil)
	if err != nil {
		return
	}
	fPanic := true
	dc.Mutex.Lock()
	defer func() {
		dc.Mutex.Unlock()

		// 如果f恐慌，fPanic将保持真实。
		// 确保将错误传递给release，以便放弃连接
		// 。
		if fPanic {
			err = driver.ErrBadConn
		}
		release(err)
	}()
	err = f(dc.ci)
	fPanic = false

	return
}

// BeginTx启动事务。
// 
// 在提交或回滚事务之前，将使用提供的上下文。
// 如果取消上下文，sql包将回滚
// 事务。如果提供给
// BeginTx的上下文被取消，则Tx.Commit将返回错误。
// 
// 提供的TXO选项是可选的，如果应该使用默认值，则可能为零。
// 如果使用了驱动程序不支持的非默认隔离级别，
// 将返回一个错误。
func (c *Conn) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
	dc, release, err := c.grabConn(ctx)
	if err != nil {
		return nil, err
	}
	return c.db.beginDC(ctx, dc, release, opts)
}

// CloseMurUnlockConditReleaseConn read解锁closemu 
// 。
func (c *Conn) closemuRUnlockCondReleaseConn(err error) {
	c.closemu.RUnlock()
	if errors.Is(err, driver.ErrBadConn) {
		c.close(err)
	}
}

func (c *Conn) txCtx() context.Context {
	return nil
}

func (c *Conn) close(err error) error {
	if !atomic.CompareAndSwapInt32(&c.done, 0, 1) {
		return ErrConnDone
	}

	// 锁定释放驱动程序连接
	// 以确保在执行此操作之前已停止所有查询。
	c.closemu.Lock()
	defer c.closemu.Unlock()

	c.dc.releaseConn(err)
	c.dc = nil
	c.db = nil
	return err
}

// Close返回到连接池的连接。
// 关闭后的所有操作都将返回并完成。
// Close可以与其他操作同时调用，并将
// 阻塞，直到所有其他操作完成。首先
// 取消任何使用过的上下文，然后直接调用close可能会很有用。
func (c *Conn) Close() error {
	return c.close(nil)
}

// Tx是一个正在进行的数据库事务。
// 
// 事务必须以提交或回滚调用结束。
// 
// 调用提交或回滚后，
// 事务上的所有操作都会失败，并返回ErrTxDone。
// 
// 通过调用
// 为事务准备的语句通过调用Commit或Rollback关闭事务的Prepare或Stmt方法
// 。
type Tx struct {
	db *DB

	// closemu阻止事务关闭，而
	// 是一个活动查询。在查询
	// 期间，它会被保存以供阅读，在关闭期间，它只会被保存。
	closemu sync.RWMutex

	// dc在提交或回滚之前为独占所有，此时
	// 将与putConn一起返回。
	dc  *driverConn
	txi driver.Tx

	// 一旦Tx关闭，就会调用releaseConn来释放
	// 任何保留的驱动器conn返回池中。
	releaseConn func(error)

	// 在提交
	// 或回滚时，从0到1的转换只完成一次。一旦完成，所有操作都会失败，
	// ErrTxDone。
	// 检查值时对值使用原子操作。
	done int32

	// 如果驱动程序知道
	// 如何重置连接的会话，并且如果需要，则放弃
	// 连接，则keepConnOnRollback为真。
	keepConnOnRollback bool

	// 为本次交易准备的所有STMT。这些将在
	// 事务提交或回滚后关闭。
	stmts struct {
		sync.Mutex
		v []*Stmt
	}

	// 在完成从0到1的转换后调用cancel。
	cancel func()

	// ctx在交易期间有效。
	ctx context.Context
}

// 等待完成，直到Tx中的上下文被取消，并回滚
// 如果事务尚未完成，则回滚该事务。
func (tx *Tx) awaitDone() {
	// 等待提交或滚动事务
	// 返回，或关闭关联的上下文。
	<-tx.ctx.Done()

	// 放弃并关闭用于确保关闭
	// 事务并释放资源的连接。如果事务已经提交或回滚，则此
	// 回滚不会执行任何操作。
	// 如果连接知道如何重置会话，请不要放弃连接。
	discardConnection := !tx.keepConnOnRollback
	tx.rollback(discardConnection)
}

func (tx *Tx) isDone() bool {
	return atomic.LoadInt32(&tx.done) != 0
}

// 对已提交或回滚的事务
// 执行的任何操作都会返回ErrTxDone。
var ErrTxDone = errors.New("sql: transaction has already been committed or rolled back")

// close返回到池的连接，
// 只能由Tx.rollback或Tx.Commit调用，而
// Tx已被取消，不会同时执行。
func (tx *Tx) close(err error) {
	tx.releaseConn(err)
	tx.dc = nil
	tx.txi = nil
}

// hookTxGrabConn指定要在
// 上调用的可选钩子成功调用（*Tx）。格拉布肯。用于测试。
var hookTxGrabConn func()

func (tx *Tx) grabConn(ctx context.Context) (*driverConn, releaseConn, error) {
	select {
	default:
	case <-ctx.Done():
		return nil, nil, ctx.Err()
	}

	// closemu。RLock必须在检查isDone之前，以防止在执行查询时发送
	// 关闭。
	tx.closemu.RLock()
	if tx.isDone() {
		tx.closemu.RUnlock()
		return nil, nil, ErrTxDone
	}
	if hookTxGrabConn != nil { // 测试钩子
		hookTxGrabConn()
	}
	return tx.dc, tx.closemuRUnlockRelease, nil
}

func (tx *Tx) txCtx() context.Context {
	return tx.ctx
}

// closemuRUnlockRelease在
// ExecContext和QueryContext中用作func（错误）方法值。解锁releaseConn将使
// 在
// 行关闭之前，驱动程序conn不会返回到连接池。
func (tx *Tx) closemuRUnlockRelease(error) {
	tx.closemu.RUnlock()
}

// 关闭为此事务准备的所有STMT。
func (tx *Tx) closePrepared() {
	tx.stmts.Lock()
	defer tx.stmts.Unlock()
	for _, stmt := range tx.stmts.v {
		stmt.Close()
	}
}

// 提交提交事务。
func (tx *Tx) Commit() error {
	// 首先检查上下文以避免事务泄漏。
	// 如果将其放在tx.done CompareAndSwap语句之后，我们无法确保tx.done和实际提交操作之间的一致性。
	select {
	default:
	case <-tx.ctx.Done():
		if atomic.LoadInt32(&tx.done) == 1 {
			return ErrTxDone
		}
		return tx.ctx.Err()
	}
	if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
		return ErrTxDone
	}

	// 取消发送以释放任何活动的R-closemu锁。
	// 这样做是安全的，因为tx.done已经将
	// 从0转换为1。在回滚
	// 之前保持W-closemu锁，以确保没有其他连接具有活动查询。
	tx.cancel()
	tx.closemu.Lock()
	tx.closemu.Unlock()

	var err error
	withLock(tx.dc, func() {
		err = tx.txi.Commit()
	})
	if !errors.Is(err, driver.ErrBadConn) {
		tx.closePrepared()
	}
	tx.close(err)
	return err
}

var rollbackHook func()

// 回滚中止事务，并选择性地强制池放弃连接。
func (tx *Tx) rollback(discardConn bool) error {
	if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
		return ErrTxDone
	}

	if rollbackHook != nil {
		rollbackHook()
	}

	// 取消发送以释放任何活动的R-closemu锁。
	// 这样做是安全的，因为tx.done已经将
	// 从0转换为1。在回滚
	// 之前保持W-closemu锁，以确保没有其他连接具有活动查询。
	tx.cancel()
	tx.closemu.Lock()
	tx.closemu.Unlock()

	var err error
	withLock(tx.dc, func() {
		err = tx.txi.Rollback()
	})
	if !errors.Is(err, driver.ErrBadConn) {
		tx.closePrepared()
	}
	if discardConn {
		err = driver.ErrBadConn
	}
	tx.close(err)
	return err
}

// 回滚将中止事务。
func (tx *Tx) Rollback() error {
	return tx.rollback(false)
}

// PrepareContext创建一条准备好的语句，供在事务中使用。
// 
// 返回的语句在事务中运行，并将在事务提交或回滚时关闭
// 返回的语句。
// 
// 要在该事务上使用现有的准备好的语句，请参阅Tx.Stmt。
// 
// 提供的上下文将用于准备上下文，而不是用于执行返回语句。返回的语句
// 将在事务上下文中运行。
func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
	dc, release, err := tx.grabConn(ctx)
	if err != nil {
		return nil, err
	}

	stmt, err := tx.db.prepareDC(ctx, dc, release, tx, query)
	if err != nil {
		return nil, err
	}
	tx.stmts.Lock()
	tx.stmts.v = append(tx.stmts.v, stmt)
	tx.stmts.Unlock()
	return stmt, nil
}

// Prepare创建一条准备好的语句，以便在事务中使用。
// 
// 返回的语句在事务中运行，并将在事务提交或回滚时关闭
// 返回的语句。
// 
// 要在该事务中使用现有的准备好的语句，请参阅Tx.Stmt。
// 
// 准备使用上下文。内部背景；要指定上下文，请使用
// PrepareContext。
func (tx *Tx) Prepare(query string) (*Stmt, error) {
	return tx.PrepareContext(context.Background(), query)
}

// StmtContext从
// 现有语句返回特定于事务的预处理语句。
// 
// 示例：
// updateMoney，err:=db。准备（“更新余额集money=money+？其中id=？”）
// /。。。
// tx，err:=db。Begin（）
// /。。。
// res，err:=tx.StmtContext（ctx，updateMoney）。Exec（123.4598293203）
// 
// 提供的上下文用于准备语句，而不是执行语句。
// 
// 返回的语句在事务中运行，并将在事务提交或回滚时关闭
// 返回的语句。
func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
	dc, release, err := tx.grabConn(ctx)
	if err != nil {
		return &Stmt{stickyErr: err}
	}
	defer release(nil)

	if tx.db != stmt.db {
		return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
	}
	var si driver.Stmt
	var parentStmt *Stmt
	stmt.mu.Lock()
	if stmt.closed || stmt.cg != nil {
		// 如果该语句已关闭或已属于
		// 事务，我们不能在这方面重用它。
		// 由于tx.StmtContext永远不需要使用已经属于tx的
		// Stmt调用，我们忽略此边缘情况和
		// 在这种情况下，重新准备陈述。无需为此添加
		// 代码复杂性。
		stmt.mu.Unlock()
		withLock(dc, func() {
			si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
		})
		if err != nil {
			return &Stmt{stickyErr: err}
		}
	} else {
		stmt.removeClosedStmtLocked()
		// 查看此连接的声明是否已经准备好，如果可能，请重新使用它。
		for _, v := range stmt.css {
			if v.dc == dc {
				si = v.ds.si
				break
			}
		}

		stmt.mu.Unlock()

		if si == nil {
			var ds *driverStmt
			withLock(dc, func() {
				ds, err = stmt.prepareOnConnLocked(ctx, dc)
			})
			if err != nil {
				return &Stmt{stickyErr: err}
			}
			si = ds.si
		}
		parentStmt = stmt
	}

	txs := &Stmt{
		db: tx.db,
		cg: tx,
		cgds: &driverStmt{
			Locker: dc,
			si:     si,
		},
		parentStmt: parentStmt,
		query:      stmt.query,
	}
	if parentStmt != nil {
		tx.db.addDep(parentStmt, txs)
	}
	tx.stmts.Lock()
	tx.stmts.v = append(tx.stmts.v, txs)
	tx.stmts.Unlock()
	return txs
}

// Stmt从
// 现有语句返回特定于事务的预处理语句。
// 
// 示例：
// updateMoney，err:=db。准备（“更新余额集money=money+？其中id=？”）
// /。。。
// tx，err:=db。Begin（）
// /。。。
// res，err:=tx.Stmt（updateMoney）。Exec（123.4598293203）
// 
// 返回的语句在事务中运行，并将在事务提交或回滚时关闭。
// 
// Stmt使用上下文。内部背景；要指定上下文，请使用
// StmtContext。
func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
	return tx.StmtContext(context.Background(), stmt)
}

// ExecContext执行不返回行的查询。
// 例如：插入和更新。
func (tx *Tx) ExecContext(ctx context.Context, query string, args ...any) (Result, error) {
	dc, release, err := tx.grabConn(ctx)
	if err != nil {
		return nil, err
	}
	return tx.db.execDC(ctx, dc, release, query, args)
}

// Exec执行一个不返回行的查询。
// 例如：插入和更新。
// 
// Exec使用上下文。内部背景；要指定上下文，请使用
// ExecContext。
func (tx *Tx) Exec(query string, args ...any) (Result, error) {
	return tx.ExecContext(context.Background(), query, args...)
}

// QueryContext执行返回行的查询，通常是SELECT。
func (tx *Tx) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error) {
	dc, release, err := tx.grabConn(ctx)
	if err != nil {
		return nil, err
	}

	return tx.db.queryDC(ctx, tx.ctx, dc, release, query, args)
}

// 查询执行返回行的查询，通常是SELECT。
// 
// 查询使用上下文。内部背景；要指定上下文，请使用
// QueryContext。
func (tx *Tx) Query(query string, args ...any) (*Rows, error) {
	return tx.QueryContext(context.Background(), query, args...)
}

// QueryRowContext执行一个最多返回一行的查询。wen dang
// 行的扫描方法时发生。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并丢弃剩余的
// 行。
func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...any) *Row {
	rows, err := tx.QueryContext(ctx, query, args...)
	return &Row{rows: rows, err: err}
}

// QueryRow执行一个最多返回一行的查询。
// QueryRow始终返回非零值。错误将推迟到调用
// 行的扫描方法时发生。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并丢弃剩余的
// 行。
// 
// QueryRow使用上下文。内部背景；要指定上下文，请使用
// QueryRowContext。
func (tx *Tx) QueryRow(query string, args ...any) *Row {
	return tx.QueryRowContext(context.Background(), query, args...)
}

// connStmt是一个关于特定连接的预先准备好的语句。
type connStmt struct {
	dc *driverConn
	ds *driverStmt
}

// stmtConnGrabber表示将返回基础
// driverConn和release函数的Tx或Conn。
type stmtConnGrabber interface {
	// grabConn返回driverConn和相关的释放函数
	// 操作完成时必须调用该函数。
	grabConn(context.Context) (*driverConn, releaseConn, error)

	// txCtx返回事务上下文（如果可用）。
	// 返回的上下文应与
	// 在等待取消时选择任何查询上下文。
	txCtx() context.Context
}

var (
	_ stmtConnGrabber = &Tx{}
	_ stmtConnGrabber = &Conn{}
)

// Stmt是一份事先准备好的声明。
// 一个Stmt对于多个Goroutine并发使用是安全的。
// 
// 如果在Tx或Conn上准备Stmt，它将永远绑定到单个
// 基础连接。如果Tx或Conn关闭，Stmt将
// 变得不可用，所有操作将返回错误。
// 。当Stmt需要在新的基础连接上执行时，它将自动在新连接上准备。
type Stmt struct {
	// Immutable:
	db        *DB    // 我们来自创建Stmt的
	query     string // 的地方
	stickyErr error  // 如果非零，则所有操作都会返回此错误

	closemu sync.RWMutex // 在关闭期间以独占方式保留，否则读取。

	// 如果Stmt是在Tx或Conn上准备的，则cg存在，并且将
	// 仅从cg获取连接。
	// 如果cg为零，则Stmt必须从db获取任意连接
	// 并确定是否必须通过
	// 检查css再次准备Stmt。当从同一
	cg   stmtConnGrabber
	cgds *driverStmt

	// 时，将设置parentStmt。parentStmt用于跟踪此语句
	// conn上准备的相同语句中请求特定于事务的语句
	// 对其原始（“父”）语句的依赖性，以便parentStmt可以
	// 用户无需知道
	// 是否有任何交易仍在使用它即可关闭。
	parentStmt *Stmt

	mu     sync.Mutex // 保护其余字段
	closed bool

	// css是一个在特定连接上有效的底层驱动程序语句接口列表
	// 。只有当cg==nil并且发现有一个连接空闲时，才使用
	// 。如果cg！=无，始终使用cgds。
	css []connStmt

	// lastNumClosed是从数据库复制的。创建Stmt时numClosed 
	// 不带tx，css中关闭的连接被删除。
	lastNumClosed uint64
}

// ExecContext使用给定的参数执行一个准备好的语句，
// 返回一个总结该语句效果的结果。
func (s *Stmt) ExecContext(ctx context.Context, args ...any) (Result, error) {
	s.closemu.RLock()
	defer s.closemu.RUnlock()

	var res Result
	strategy := cachedOrNewConn
	for i := 0; i < maxBadConnRetries+1; i++ {
		if i == maxBadConnRetries {
			strategy = alwaysNewConn
		}
		dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
		if err != nil {
			if errors.Is(err, driver.ErrBadConn) {
				continue
			}
			return nil, err
		}

		res, err = resultFromStatement(ctx, dc.ci, ds, args...)
		releaseConn(err)
		if !errors.Is(err, driver.ErrBadConn) {
			return res, err
		}
	}
	return nil, driver.ErrBadConn
}

// Exec使用给定的参数执行一个准备好的语句，
// 返回一个总结该语句效果的结果。
// 
// Exec使用上下文。内部背景；要指定上下文，请使用
// ExecContext。
func (s *Stmt) Exec(args ...any) (Result, error) {
	return s.ExecContext(context.Background(), args...)
}

func resultFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...any) (Result, error) {
	ds.Lock()
	defer ds.Unlock()

	dargs, err := driverArgsConnLocked(ci, ds, args)
	if err != nil {
		return nil, err
	}

	resi, err := ctxDriverStmtExec(ctx, ds.si, dargs)
	if err != nil {
		return nil, err
	}
	return driverResult{ds.Locker, resi}, nil
}

// removeClosedStmtLocked删除s.css中的闭合连接。
// 
// 避免数据库上的锁争用。穆，我们只有在
// s.db时才这么做。numClosed-s.lastNum足够大了。
func (s *Stmt) removeClosedStmtLocked() {
	t := len(s.css)/2 + 1
	if t > 10 {
		t = 10
	}
	dbClosed := atomic.LoadUint64(&s.db.numClosed)
	if dbClosed-s.lastNumClosed < uint64(t) {
		return
	}

	s.db.mu.Lock()
	for i := 0; i < len(s.css); i++ {
		if s.css[i].dc.dbmuClosed {
			s.css[i] = s.css[len(s.css)-1]
			s.css = s.css[:len(s.css)-1]
			i--
		}
	}
	s.db.mu.Unlock()
	s.lastNumClosed = dbClosed
}

// connStmt返回一个自由驱动程序连接，在该连接上执行
// 语句，一个用于调用以释放连接的函数，以及一个绑定到该连接的
// 语句。
func (s *Stmt) connStmt(ctx context.Context, strategy connReuseStrategy) (dc *driverConn, releaseConn func(error), ds *driverStmt, err error) {
	if err = s.stickyErr; err != nil {
		return
	}
	s.mu.Lock()
	if s.closed {
		s.mu.Unlock()
		err = errors.New("sql: statement is closed")
		return
	}

	// 在事务或连接中，我们始终使用创建
	// stmt的连接。
	if s.cg != nil {
		s.mu.Unlock()
		dc, releaseConn, err = s.cg.grabConn(ctx) // 阻塞，等待连接。
		if err != nil {
			return
		}
		return dc, releaseConn, s.cgds, nil
	}

	s.removeClosedStmtLocked()
	s.mu.Unlock()

	dc, err = s.db.conn(ctx, strategy)
	if err != nil {
		return nil, nil, nil, err
	}

	s.mu.Lock()
	for _, v := range s.css {
		if v.dc == dc {
			s.mu.Unlock()
			return dc, dc.releaseConn, v.ds, nil
		}
	}
	s.mu.Unlock()

	// 运气不好；我们需要准备关于这个连接的语句
	withLock(dc, func() {
		ds, err = s.prepareOnConnLocked(ctx, dc)
	})
	if err != nil {
		dc.releaseConn(err)
		return nil, nil, nil, err
	}

	return dc, dc.releaseConn, ds, nil
}

// prepareonconlocked在dc上的Stmt s中准备查询，并将其添加到
// open connStmt的列表中。它假定调用方持有dc上的锁。
func (s *Stmt) prepareOnConnLocked(ctx context.Context, dc *driverConn) (*driverStmt, error) {
	si, err := dc.prepareLocked(ctx, s.cg, s.query)
	if err != nil {
		return nil, err
	}
	cs := connStmt{dc, si}
	s.mu.Lock()
	s.css = append(s.css, cs)
	s.mu.Unlock()
	return cs.ds, nil
}

// QueryContext使用给定参数执行准备好的查询语句
// 并以*行的形式返回查询结果。
func (s *Stmt) QueryContext(ctx context.Context, args ...any) (*Rows, error) {
	s.closemu.RLock()
	defer s.closemu.RUnlock()

	var rowsi driver.Rows
	strategy := cachedOrNewConn
	for i := 0; i < maxBadConnRetries+1; i++ {
		if i == maxBadConnRetries {
			strategy = alwaysNewConn
		}
		dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
		if err != nil {
			if errors.Is(err, driver.ErrBadConn) {
				continue
			}
			return nil, err
		}

		rowsi, err = rowsiFromStatement(ctx, dc.ci, ds, args...)
		if err == nil {
			// 注意：ci的所有权转移到*行，将通过releaseConn释放
			// 。
			rows := &Rows{
				dc:    dc,
				rowsi: rowsi,
				// 
			}
			// addDep必须在initContextClose之前添加，或者它可以尝试在添加之前删除
			// 。
			s.db.addDep(s, rows)

			// 必须在initContextClose之前设置releaseConn，否则可能会在设置之前释放连接。
			rows.releaseConn = func(err error) {
				releaseConn(err)
				s.db.removeDep(s, rows)
			}
			var txctx context.Context
			if s.cg != nil {
				txctx = s.cg.txCtx()
			}
			rows.initContextClose(ctx, txctx)
			return rows, nil
		}

		releaseConn(err)
		if !errors.Is(err, driver.ErrBadConn) {
			return nil, err
		}
	}
	return nil, driver.ErrBadConn
}

// Query使用给定的参数执行一条准备好的查询语句
// 并将查询结果作为*行返回。
// 
// 查询使用上下文。内部背景；要指定上下文，请使用
// QueryContext。
func (s *Stmt) Query(args ...any) (*Rows, error) {
	return s.QueryContext(context.Background(), args...)
}

func rowsiFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...any) (driver.Rows, error) {
	ds.Lock()
	defer ds.Unlock()
	dargs, err := driverArgsConnLocked(ci, ds, args)
	if err != nil {
		return nil, err
	}
	return ctxDriverStmtQuery(ctx, ds.si, dargs)
}

// QueryRowContext使用给定参数执行准备好的查询语句。
// 如果在语句执行过程中发生错误，则该错误将由对返回的*行进行扫描的调用返回，该行始终为非零。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并丢弃剩余的
// 行。
func (s *Stmt) QueryRowContext(ctx context.Context, args ...any) *Row {
	rows, err := s.QueryContext(ctx, args...)
	if err != nil {
		return &Row{err: err}
	}
	return &Row{rows: rows}
}

// QueryRow使用给定参数执行准备好的查询语句。
// 如果在语句执行过程中发生错误，则该错误将由对返回的*行进行扫描的调用返回，该行始终为非零。
// 如果查询没有选择任何行，*行的扫描将返回errnorow。
// 否则，*行的扫描将扫描第一个选定的行，并丢弃剩余的
// 行。
// 
// 示例用法：
// 
// var name string 
// err:=nameByUseridStmt。克雷罗（id）。扫描（&名称）
// 
// QueryRow使用上下文。内部背景；要指定上下文，请使用
// QueryRowContext。
func (s *Stmt) QueryRow(args ...any) *Row {
	return s.QueryRowContext(context.Background(), args...)
}

// Close结束语句。
func (s *Stmt) Close() error {
	s.closemu.Lock()
	defer s.closemu.Unlock()

	if s.stickyErr != nil {
		return s.stickyErr
	}
	s.mu.Lock()
	if s.closed {
		s.mu.Unlock()
		return nil
	}
	s.closed = true
	txds := s.cgds
	s.cgds = nil

	s.mu.Unlock()

	if s.cg == nil {
		return s.db.removeDep(s, s)
	}

	if s.parentStmt != nil {
		// 如果设置了parentStmt，我们不能关闭s.txds，因为它存储在parentStmt的css数组中。
		return s.db.removeDep(s.parentStmt, s)
	}
	return txds.Close()
}

func (s *Stmt) finalClose() error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.css != nil {
		for _, v := range s.css {
			s.db.noteUnusedDriverStatement(v.dc, v.ds)
			v.dc.removeOpenStmt(v.ds)
		}
		s.css = nil
	}
	return nil
}

// 行是查询的结果。其光标在结果集的第一行
// 之前开始。使用“下一步”从一行前进到另一行。
type Rows struct {
	dc          *driverConn // 所有；关闭时必须调用releaseConn才能释放
	releaseConn func(error)
	rowsi       driver.Rows
	cancel      func()      // 行关闭时调用，可能为零。
	closeStmt   *driverStmt // 如果非nil，则在关闭时关闭语句

	// 当
	// 是活动流式处理结果时，closemu阻止行关闭。在非关闭操作
	// 且仅在关闭期间。
	// 
	// closemu守卫最后一次并关闭。
	closemu sync.RWMutex
	closed  bool
	lasterr error // 仅当closed为true时非nil 

	// lastcols仅用于扫描、下一步和下一步结果集，这些结果集预计
	// 不会同时调用。
	lastcols []driver.Value
}

// lastErrorErrorLocked返回lasterr或提供的错误。
// rs.closemu必须被读取锁定。
func (rs *Rows) lasterrOrErrLocked(err error) error {
	if rs.lasterr != nil && rs.lasterr != io.EOF {
		return rs.lasterr
	}
	return err
}

// bypassRowsAwaitDone仅用于测试。
// 如果为true，则不会从上下文自动关闭行。
var bypassRowsAwaitDone = false

func (rs *Rows) initContextClose(ctx, txctx context.Context) {
	if ctx.Done() == nil && (txctx == nil || txctx.Done() == nil) {
		return
	}
	if bypassRowsAwaitDone {
		return
	}
	ctx, rs.cancel = context.WithCancel(ctx)
	go rs.awaitDone(ctx, txctx)
}

// 等待完成，直到ctx或txctx被取消。ctx是从查询上下文
// 提供的，在查询行关闭时取消。
// 如果查询是在事务中发出的，则txctx中还提供了事务的上下文
// 以确保在关闭Tx时关闭行。
func (rs *Rows) awaitDone(ctx, txctx context.Context) {
	var txctxDone <-chan struct{}
	if txctx != nil {
		txctxDone = txctx.Done()
	}
	select {
	case <-ctx.Done():
	case <-txctxDone:
	}
	rs.close(ctx.Err())
}

// 下一步准备下一个结果行，以便使用扫描方法读取。成功时返回true，如果没有下一个结果行或在准备时发生错误，返回false。应咨询Err以区分
// 这两种情况。
// 
// 每次调用Scan，即使是第一次，都必须在调用Next之前进行。
func (rs *Rows) Next() bool {
	var doClose, ok bool
	withLock(rs.closemu.RLocker(), func() {
		doClose, ok = rs.nextLocked()
	})
	if doClose {
		rs.Close()
	}
	return ok
}

func (rs *Rows) nextLocked() (doClose, ok bool) {
	if rs.closed {
		return false, false
	}

	// 在调用驱动程序接口
	// rowsi之前锁定驱动程序连接，以防止Tx同时回滚连接。
	rs.dc.Lock()
	defer rs.dc.Unlock()

	if rs.lastcols == nil {
		rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
	}

	rs.lasterr = rs.rowsi.Next(rs.lastcols)
	if rs.lasterr != nil {
		// 如果出现驱动程序错误，请关闭连接。
		if rs.lasterr != io.EOF {
			return true, false
		}
		nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
		if !ok {
			return true, false
		}
		// 驱动程序位于当前结果集的末尾。
		// 测试当前结果集之后是否还有其他结果集。
		// 只有在没有其他结果集可读取时才关闭行。
		if !nextResultSet.HasNextResultSet() {
			doClose = true
		}
		return doClose, false
	}
	return false, true
}

// NextResultSet准备读取下一个结果集。它报告
// 是否有进一步的结果集，或者如果没有进一步的结果集
// 或者前进到该结果集时出错，则报告false。应参考
// 的Err方法来区分这两种情况。
// 
// 调用NextResultSet后，应始终在
// 扫描之前调用下一个方法。如果有更多的结果集，则结果
// 集中可能没有行。
func (rs *Rows) NextResultSet() bool {
	var doClose bool
	defer func() {
		if doClose {
			rs.Close()
		}
	}()
	rs.closemu.RLock()
	defer rs.closemu.RUnlock()

	if rs.closed {
		return false
	}

	rs.lastcols = nil
	nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
	if !ok {
		doClose = true
		return false
	}

	// 在调用驱动程序接口
	// rowsi之前锁定驱动程序连接，以防止Tx同时回滚连接。
	rs.dc.Lock()
	defer rs.dc.Unlock()

	rs.lasterr = nextResultSet.NextResultSet()
	if rs.lasterr != nil {
		doClose = true
		return false
	}
	return true
}

// Err返回迭代过程中遇到的错误（如果有）。
// Err可以在显式或隐式关闭后调用。
func (rs *Rows) Err() error {
	rs.closemu.RLock()
	defer rs.closemu.RUnlock()
	return rs.lasterrOrErrLocked(nil)
}

var errRowsClosed = errors.New("sql: Rows are closed")
var errNoRows = errors.New("sql: no Rows available")

// Columns返回列名。
// 如果行关闭，列将返回错误。
func (rs *Rows) Columns() ([]string, error) {
	rs.closemu.RLock()
	defer rs.closemu.RUnlock()
	if rs.closed {
		return nil, rs.lasterrOrErrLocked(errRowsClosed)
	}
	if rs.rowsi == nil {
		return nil, rs.lasterrOrErrLocked(errNoRows)
	}
	rs.dc.Lock()
	defer rs.dc.Unlock()

	return rs.rowsi.Columns(), nil
}

// ColumnTypes返回列类型、长度、
// 和nullable等列信息。某些驾驶员可能无法提供某些信息。
func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
	rs.closemu.RLock()
	defer rs.closemu.RUnlock()
	if rs.closed {
		return nil, rs.lasterrOrErrLocked(errRowsClosed)
	}
	if rs.rowsi == nil {
		return nil, rs.lasterrOrErrLocked(errNoRows)
	}
	rs.dc.Lock()
	defer rs.dc.Unlock()

	return rowsColumnInfoSetupConnLocked(rs.rowsi), nil
}

// ColumnType包含列的名称和类型。
type ColumnType struct {
	name string

	hasNullable       bool
	hasLength         bool
	hasPrecisionScale bool

	nullable     bool
	length       int64
	databaseType string
	precision    int64
	scale        int64
	scanType     reflect.Type
}

// Name返回列的名称或别名。
func (ci *ColumnType) Name() string {
	return ci.name
}

// Length返回可变长度列类型的列类型长度，如文本和二进制字段类型。如果类型长度是无界的，则该值将为
// math。MaxInt64（任何数据库限制仍将适用）。
// 如果列类型不是可变长度，例如int，或者如果驱动程序不支持
// 则ok为false。
func (ci *ColumnType) Length() (length int64, ok bool) {
	return ci.length, ci.hasLength
}

// DecimalSize返回十进制类型的小数位数和精度。
// 如果不适用或不受支持，则ok为假。
func (ci *ColumnType) DecimalSize() (precision, scale int64, ok bool) {
	return ci.precision, ci.scale, ci.hasPrecisionScale
}

// ScanType返回一个适合使用行扫描的Go类型。扫描
// 如果驱动程序不支持此属性，ScanType将返回
// 空接口的类型。
func (ci *ColumnType) ScanType() reflect.Type {
	return ci.scanType
}

// Nullable报告列是否可以为null。
// 如果驱动程序不支持此属性，ok将为false。
func (ci *ColumnType) Nullable() (nullable, ok bool) {
	return ci.nullable, ci.hasNullable
}

// DatabaseTypeName返回列类型的数据库系统名称。如果返回空的
// 字符串，则不支持驱动程序类型名称。
// 有关驱动程序数据类型的列表，请查阅驱动程序文档。长度说明符
// 不包括在内。
// 常见的类型名称包括“VARCHAR”、“TEXT”、“NVARCHAR”、“DECIMAL”、“BOOL”、
// “INT”和“BIGINT”。
func (ci *ColumnType) DatabaseTypeName() string {
	return ci.databaseType
}

func rowsColumnInfoSetupConnLocked(rowsi driver.Rows) []*ColumnType {
	names := rowsi.Columns()

	list := make([]*ColumnType, len(names))
	for i := range list {
		ci := &ColumnType{
			name: names[i],
		}
		list[i] = ci

		if prop, ok := rowsi.(driver.RowsColumnTypeScanType); ok {
			ci.scanType = prop.ColumnTypeScanType(i)
		} else {
			ci.scanType = reflect.TypeOf(new(any)).Elem()
		}
		if prop, ok := rowsi.(driver.RowsColumnTypeDatabaseTypeName); ok {
			ci.databaseType = prop.ColumnTypeDatabaseTypeName(i)
		}
		if prop, ok := rowsi.(driver.RowsColumnTypeLength); ok {
			ci.length, ci.hasLength = prop.ColumnTypeLength(i)
		}
		if prop, ok := rowsi.(driver.RowsColumnTypeNullable); ok {
			ci.nullable, ci.hasNullable = prop.ColumnTypeNullable(i)
		}
		if prop, ok := rowsi.(driver.RowsColumnTypePrecisionScale); ok {
			ci.precision, ci.scale, ci.hasPrecisionScale = prop.ColumnTypePrecisionScale(i)
		}
	}
	return list
}

// 扫描将当前行中的列复制到dest指向的值中。dest中的值数必须与
// 行中的列数相同。
// 
// Scan将从数据库读取的列转换为以下sql包提供的常见Go类型和特殊类型：
// 
// /*字符串
// /*[]字节
// /*int，*int8，*int16，*int32，*int64 
// /*uint，*t8，*uint16，*uint32，*uint64 
// /*bool 
// /*float32，*float64 
// /*接口{}
// /*RawBytes 
// /*行（光标值）
// /任何类型的实现扫描程序（参见扫描文档）
// /
// 列中的值的类型是整数、bool或string类型T，dest的类型是*T，
// Scan只需通过指针分配值。
// 
// 扫描还可以在字符串和数字类型之间进行转换，前提是不会丢失任何
// 信息。扫描字符串化所有数字
// 从数字数据库列扫描到*字符串，扫描到
// 检查数字类型是否溢出。例如，带有
// 值300的float64或带有值“300”的字符串可以扫描到uint16，但
// 不能扫描到uint8，尽管float64（255）或“255”可以扫描到
// uint8。一个例外是，当字符串化时，对
// 字符串的一些float64数字的扫描可能会丢失信息。通常，将
// 浮点列扫描到*float64中。
// 
// 如果dest参数的类型为*[]字节，Scan会在该参数中保存相应数据的副本。该副本归调用方所有，
// 可以修改并无限期保留。可以通过
// 使用*RawBytes类型的参数来避免复制；请参阅文档
// 了解RawBytes以了解其使用限制。
// 
// 如果参数的类型为*接口{}，则扫描会复制底层驱动程序提供的值
// 而不进行转换。当将
// 从类型为[]字节的源值扫描到*接口{}时，将生成
// 切片的副本，调用方拥有结果。
// 
// 时间类型的源值。时间可以扫描为
// /*时间类型的值。时间、*接口{}、*字符串或*[]字节。当转换成
// 后两个，时间。使用RFC3339Nano。
// 
// bool类型的源值可以扫描为*bool、
// /*接口{}、*string、*[]字节或*RawBytes类型。
// 
// 扫描到*bool时，源代码可以是true、false、1、0或
// 可由strconv解析的字符串输入。帕斯布尔。
// 
// Scan还可以将查询返回的游标（如
// “select cursor（select*from my_table）from dual”）转换为
// *行值，该行值本身可以从中进行扫描。父
// 如果父*行关闭，select查询将关闭所有游标*行。
// 
// 如果实现Scanner的任何第一个参数返回错误，
// 该错误将被包装在返回的错误
func (rs *Rows) Scan(dest ...any) error {
	rs.closemu.RLock()

	if rs.lasterr != nil && rs.lasterr != io.EOF {
		rs.closemu.RUnlock()
		return rs.lasterr
	}
	if rs.closed {
		err := rs.lasterrOrErrLocked(errRowsClosed)
		rs.closemu.RUnlock()
		return err
	}
	rs.closemu.RUnlock()

	if rs.lastcols == nil {
		return errors.New("sql: Scan called without calling Next")
	}
	if len(dest) != len(rs.lastcols) {
		return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
	}
	for i, sv := range rs.lastcols {
		err := convertAssignRows(dest[i], sv, rs)
		if err != nil {
			return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err)
		}
	}
	return nil
}

// rowsCloseHook返回一个函数，以便测试可以通过仅测试的互斥锁安装
// 挂钩。
var rowsCloseHook = func() func(*Rows, *error) { return nil }

// Close关闭行，防止进一步枚举。如果Next名为
// 并返回false，并且没有进一步的结果集，则
// 行将自动关闭，只需检查错误的
// 结果即可。Close是幂等的，不影响Err的结果。
func (rs *Rows) Close() error {
	return rs.close(nil)
}

func (rs *Rows) close(err error) error {
	rs.closemu.Lock()
	defer rs.closemu.Unlock()

	if rs.closed {
		return nil
	}
	rs.closed = true

	if rs.lasterr == nil {
		rs.lasterr = err
	}

	withLock(rs.dc, func() {
		err = rs.rowsi.Close()
	})
	if fn := rowsCloseHook(); fn != nil {
		fn(rs, &err)
	}
	if rs.cancel != nil {
		rs.cancel()
	}

	if rs.closeStmt != nil {
		rs.closeStmt.Close()
	}
	rs.releaseConn(err)
	return err
}

// 行是调用QueryRow选择一行的结果。
type Row struct {
	// 这两个值中的一个将为非零：
	err  error // 容易链接的延迟错误
	rows *Rows
}

// 扫描将匹配行中的列复制到dest指向的值
// 中。请参阅有关行的文档。扫描细节。
// 如果有多行与查询匹配，
// 扫描将使用第一行并丢弃其余行。如果没有与
// 查询匹配的行，Scan将返回ERRNOWS。
func (r *Row) Scan(dest ...any) error {
	if r.err != nil {
		return r.err
	}

	// TODO（bradfitz）：现在我们需要防御性地克隆驱动程序返回的所有
	// []字节（不允许
	// *RawBytes in Rows.Scan），因为当我们从这个函数返回时，我们将关闭
	// /延迟中的行。
	// 与司机的合同。下一个（…）接口是它
	// 可以将片返回到只读临时内存
	// 只在下次扫描/关闭之前有效。但是要做的是
	// 对于很多司机来说，这个副本是不必要的。我们
	// 应该为
	// 实现的驱动程序提供一个可选接口，以表示：“别担心，我从Next返回的[]字节将不会被再次修改。”（例如，如果
	// 他们无论如何都是从网络上获得的）但现在我们
	// 不在乎。
	defer r.rows.Close()
	for _, dp := range dest {
		if _, ok := dp.(*RawBytes); ok {
			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
		}
	}

	if !r.rows.Next() {
		if err := r.rows.Err(); err != nil {
			return err
		}
		return ErrNoRows
	}
	err := r.rows.Scan(dest...)
	if err != nil {
		return err
	}
	// 确保查询可以处理到完成，没有错误。
	return r.rows.Close()
}

// Err提供了一种包装包的方法，可以在不调用Scan的情况下检查
// 查询错误。
// Err返回运行查询时遇到的错误（如果有）。
// 如果此错误不是零，扫描时也会返回此错误。
func (r *Row) Err() error {
	return r.err
}

// 结果总结了执行的SQL命令。
type Result interface {
	// LastInsertId返回数据库
	// 响应命令生成的整数。通常，插入新行时，这将来自
	// /“自动增量”列。并非所有的
	// 数据库都支持此功能，而且此类
	// 语句的语法各不相同。
	LastInsertId() (int64, error)

	// RowsAffected返回受
	// 更新、插入或删除影响的行数。并非每个数据库或数据库
	// 驱动程序都支持此功能。
	RowsAffected() (int64, error)
}

type driverResult struct {
	sync.Locker // 带锁的*driverConn 
	resi        driver.Result
}

func (dr driverResult) LastInsertId() (int64, error) {
	dr.Lock()
	defer dr.Unlock()
	return dr.resi.LastInsertId()
}

func (dr driverResult) RowsAffected() (int64, error) {
	dr.Lock()
	defer dr.Unlock()
	return dr.resi.RowsAffected()
}

func stack() string {
	var buf [2 << 10]byte
	return string(buf[:runtime.Stack(buf[:], false)])
}

// 在按住lk的同时运行。
func withLock(lk sync.Locker, fn func()) {
	lk.Lock()
	defer lk.Unlock() // 如果fn恐慌
	fn()
}
